from expression import expression
from jsobject import *
from endvals import *
import sys
sys.path.append(sys.path[0] + "/../LLVM")
from llvmhelper import llvmHelper
from llvm import *
from commonRoutines import commonRoutines



class plus(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env)

		if(	not( 		
								(
									type(lval) == type(0) or
						  			type(lval) == type(0.0)
						  		) 
						  and 
						  		(
						  			type(rval) == type(0) or 
						  			type(rval) == type(0.0)
						  		)
						 ) 
			and 
				 not 	(
				 			isinstance(lval, stringval) and 
				 			isinstance(rval, stringval)
				 			)
			):
			print "Error: + requires <int> or <float> found"

		return lval + rval
		
	def toLLVM(self, helper):
		helper.descend("plus")
		c = commonRoutines(helper)
		
		self.lval.toLLVM(helper)
		self.rval.toLLVM(helper)

		argValues = helper.getReturns()
		endResult =  c.floatIntBinaryOp(argValues[0], argValues[1], llvm_add("","",""), llvm_add("","","","float"), False, 0)
		helper.setLabel(endResult[0])
		helper.ascend(endResult[1])
	
	def traverse(self, helper):
		self.lval.traverse(helper)
		self.rval.traverse(helper)
		

class minus(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
		
	def evaluate(self, env):
		#print "lval : " + str(self.lval) + " | rval : " + str(self.rval)
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		#print "'n Evaled: lval : " + str(lval) + " | rval : " + str(rval)
		if(not((type(lval) == type(0) or type(lval) == type(0.0)) and (type(rval) == type(0) or type(rval) == type(0.0)))):
			print "Error: - requires <int> or <float> found " + type(lval) + " " + type(rval) + "\n"
		#print "\nIn builtin. lval: ",lval, " rval: ",rval
		return lval - rval
	
	def toLLVM(self, helper):
		helper.descend("minus")
		c = commonRoutines(helper)
		
		self.lval.toLLVM(helper)
		self.rval.toLLVM(helper)

		argValues = helper.getReturns()
		endResult =  c.floatIntBinaryOp(argValues[0], argValues[1], llvm_sub("","",""), llvm_sub("","","","float"), False, 1)
		helper.setLabel(endResult[0])
		helper.ascend(endResult[1])
		
	def traverse(self, helper):
		self.lval.traverse(helper)
		self.rval.traverse(helper)

class mult(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	
	def toLLVM(self, helper):
		helper.descend("mult")
		c = commonRoutines(helper)
		
		self.lval.toLLVM(helper)
		self.rval.toLLVM(helper)

		argValues = helper.getReturns()
		endResult =  c.floatIntBinaryOp(argValues[0], argValues[1], llvm_mult("","",""), llvm_mult("","","","float"), False, 2)
		helper.setLabel(endResult[0])
		helper.ascend(endResult[1])
		
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		if(not((type(lval) == type(0) or type(lval) == type(0.0)) and (type(rval) == type(0) or type(rval) == type(0.0)))):
			print "Error: * requires <int> or <float> found " + type(lval) + " " + type(rval) + "\n"
		return lval * rval
		
	def traverse(self, helper):
		self.lval.traverse(helper)
		self.rval.traverse(helper)

class div(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
		
	def toLLVM(self, helper):
		helper.descend("div")
		c = commonRoutines(helper)
		
		self.lval.toLLVM(helper)
		self.rval.toLLVM(helper)

		argValues = helper.getReturns()
		endResult =  c.floatIntBinaryOp(argValues[0], argValues[1], llvm_idiv("","",""), llvm_fdiv("","","","float"), False, 3)
		helper.setLabel(endResult[0])
		helper.ascend(endResult[1])
		
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		if(not((type(lval) == type(0) or type(lval) == type(0.0)) and (type(rval) == type(0) or type(rval) == type(0.0)))):
			print "Error: / requires <int> or <float> found " + type(lval) + " " + type(rval) + "\n"
		return lval / rval
		
	def traverse(self, helper):
		self.lval.traverse(helper)
		self.rval.traverse(helper)

class lessThan(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	
	def toLLVM(self, helper):
		helper.descend("lessThan")
		c = commonRoutines(helper)
		
		self.lval.toLLVM(helper)
		self.rval.toLLVM(helper)

		argValues = helper.getReturns()
		endResult =  c.floatIntBinaryOp(argValues[0], argValues[1], llvm_icmp_slt("","",""), llvm_fcmp_slt("","",""), True, 4)
		helper.setLabel(endResult[0])
		helper.ascend(endResult[1])
		
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		if(not((type(lval) == type(0) or type(lval) == type(0.0)) and (type(rval) == type(0) or type(rval) == type(0.0)))):
			print "Error: < requires <int> or <float> found " + type(lval) + " " + type(rval) + "\n"
		return lval < rval
		
	def traverse(self, helper):
		self.lval.traverse(helper)
		self.rval.traverse(helper)

class greatThan(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		if(not((type(lval) == type(0) or type(lval) == type(0.0)) and (type(rval) == type(0) or type(rval) == type(0.0)))):
			print "Error: > requires <int> or <float> found " + type(lval) + " " + type(rval) + "\n"
		#print "\nIn builtin. lval: ",lval, " rval: ",rval
		return lval > rval
		
	def toLLVM(self, helper):
		helper.descend("greatThan")
		c = commonRoutines(helper)
		
		self.lval.toLLVM(helper)
		self.rval.toLLVM(helper)

		argValues = helper.getReturns()
		endResult =  c.floatIntBinaryOp(argValues[1], argValues[0], llvm_icmp_slt("","",""), llvm_fcmp_slt("","",""), True, 5)
		helper.setLabel(endResult[0])
		helper.ascend(endResult[1])
		
	def traverse(self, helper):
		self.lval.traverse(helper)
		self.rval.traverse(helper)

class lessEq(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		if(not((type(lval) == type(0) or type(lval) == type(0.0)) and (type(rval) == type(0) or type(rval) == type(0.0)))):
			print "Error: <= requires <int> or <float> found " + type(lval) + " " + type(rval) + "\n"
		return lval <= rval
		
	def toLLVM(self, helper):
		helper.descend("lessEq")
		c = commonRoutines(helper)
		
		self.lval.toLLVM(helper)
		self.rval.toLLVM(helper)

		argValues = helper.getReturns()
		endResult =  c.floatIntBinaryOp(argValues[0], argValues[1], llvm_icmp_sle("","",""), llvm_fcmp_sle("","",""), True, 6)
		helper.setLabel(endResult[0])
		helper.ascend(endResult[1])
		
	def traverse(self, helper):
		self.lval.traverse(helper)
		self.rval.traverse(helper)

class greatEq(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		if(not((type(lval) == type(0) or type(lval) == type(0.0)) and (type(rval) == type(0) or type(rval) == type(0.0)))):
			print "Error: >= requires <int> or <float> found " + type(lval) + " " + type(rval) + "\n"
		return lval >= rval
		
	def toLLVM(self, helper):
		helper.descend("greatEq")
		c = commonRoutines(helper)
		
		self.lval.toLLVM(helper)
		self.rval.toLLVM(helper)

		argValues = helper.getReturns()
		endResult =  c.floatIntBinaryOp(argValues[1], argValues[0], llvm_icmp_sle("","",""), llvm_fcmp_sle("","",""), True, 7)
		helper.setLabel(endResult[0])
		helper.ascend(endResult[1])

	def traverse(self, helper):
		self.lval.traverse(helper)
		self.rval.traverse(helper)

class and_(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		if((type(lval) != type(1==1)) or (type(rval) != type(1==1))):
			print "Error: and_ requires <bool> found " + type(lval) + " " + type(rval) + "\n"
		return lval and rval
	def toLLVM(self, helper):
		helper.descend("and")
		self.lval.toLLVM(helper)
		self.rval.toLLVM(helper)
		
		c = commonRoutines(helper)
		
		argValues = helper.getReturns()
		#Labels
		firstNumi1 = helper.getNextLabel()
		errorLabel = helper.getNextLabel()
		endlabel = helper.getNextLabel()
		#Registers
		shiftReg1 = helper.getNextReg()
		shiftReg2 = helper.getNextReg()
		preShiftReg = helper.getNextReg()
		postShiftReg =helper.getNextReg() 
		targetReg = helper.getNextReg()
		
		#helper.addLLVMLine(maskReg1  + " = and i32 " + argValues[0] + ", 3")
		#helper.addLLVMLine(branchReg1 + " = icmp eq i32 " + maskReg1 + ", 3")
		#helper.addLLVMLine( "br  i1 " + branchReg1 + ", label %" + firstNumi32 + ", label  %" + errorLabel)
		c.checkType(argValues[0], "bool", firstNumi1, errorLabel)
		
		helper.addLLVMLabel(firstNumi1)

#		helper.addLLVMLine(maskReg2  + " = and i32 " + argValues[1] + ", 3")
#		helper.addLLVMLine(branchReg2 + " = icmp eq i32 " + maskReg2 + ", 3")
#		helper.addLLVMLine( "br  i1 " + branchReg2 + ", label  %" + endlabel + ", label  %" + errorLabel)
		c.checkType(argValues[1], "bool", endlabel, errorLabel)
		
		helper.addLLVMLabel(errorLabel)
		c.signalError(8)
#		helper.addLLVMLine( "call void @printerror(i32 8) noreturn")
#		helper.addLLVMLine( "unreachable")
		
		helper.addLLVMLabel(endlabel)
		helper.addLLVMInst(llvm_lshr(shiftReg1, argValues[0], "2"), "Shifting down arg 1")
		helper.addLLVMInst(llvm_lshr(shiftReg2, argValues[1], "2"), "Shifting down arg 2")
		helper.addLLVMInst(llvm_and(preShiftReg, shiftReg1, shiftReg2), "And the shifted reg's")
		helper.addLLVMInst(llvm_shl(postShiftReg, preShiftReg, "2"), "Shift result back")
		helper.addLLVMInst(llvm_add(targetReg, postShiftReg, "3"), "add tag value")
#		helper.addLLVMLine(shiftReg1 + " = lshr i32 " + argValues[0] + ", 2")
#		helper.addLLVMLine(shiftReg2 + " = lshr i32 " + argValues[1] + ", 2")
#		helper.addLLVMLine(preShiftReg + " = and i1 " + argValues[0] + ", " + argValues[1])
#		helper.addLLVMLine(postShiftReg + " = shl i32 " + preShiftReg + ", 2")
#		helper.addLLVMLine(targetReg + " = add i32 " + postShiftReg + ", 3")
		
		helper.setLabel(endlabel)
		helper.ascend(targetReg)
		
	def traverse(self, helper):
		self.lval.traverse(helper)
		self.rval.traverse(helper)

class or_(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		if((type(lval) != type(1==1)) or (type(rval) != type(1==1))):
			print "Error: or_ requires <bool> found " + type(lval) + " " + type(rval) + "\n"
		return lval or rval
	def toLLVM(self, helper):
		helper.descend("and")
		self.lval.toLLVM(helper)
		self.rval.toLLVM(helper)
		
		c = commonRoutines(helper)
		
		argValues = helper.getReturns()
		#Labels
		firstNumi1 = helper.getNextLabel()
		errorLabel = helper.getNextLabel()
		endlabel = helper.getNextLabel()
		#Registers
		shiftReg1 = helper.getNextReg()
		shiftReg2 = helper.getNextReg()
		preShiftReg = helper.getNextReg()
		postShiftReg =helper.getNextReg() 
		targetReg = helper.getNextReg()
		
		c.checkType(argValues[0], "bool", firstNumi1, errorLabel)
		
		helper.addLLVMLabel(firstNumi1)

		c.checkType(argValues[1], "bool", endlabel, errorLabel)
		
		helper.addLLVMLabel(errorLabel)
		c.signalError(9)
		
		helper.addLLVMLabel(endlabel)
		helper.addLLVMInst(llvm_lshr(shiftReg1, argValues[0], "2"), "Shifting down arg 1")
		helper.addLLVMInst(llvm_lshr(shiftReg2, argValues[1], "2"), "Shifting down arg 2")
		helper.addLLVMInst(llvm_or(preShiftReg, shiftReg1, shiftReg2), "And the shifted reg's")
		helper.addLLVMInst(llvm_shl(postShiftReg, preShiftReg, "2"), "Shift result back")
		helper.addLLVMInst(llvm_add(targetReg, postShiftReg, "3"), "add tag value")
		
		helper.setLabel(endlabel)
		helper.ascend(targetReg)

	def traverse(self, helper):
		self.lval.traverse(helper)
		self.rval.traverse(helper)

class not_(expression):
	def __init__(self,val):
		self.val = val
	def evaluate(self, env):
		val = self.val.evaluate(env) 
		if(type(val) != type(1==1)):
			print "Error: not_ requires <bool> found " + type(val) + "\n"
		return not val
		
	def toLLVM(self, helper):
		helper.descend("not")
		self.val.toLLVM(helper)
		
		c = commonRoutines(helper)
		
		argValues = helper.getReturns()
		#Labels
		errorLabel = helper.getNextLabel()
		endlabel = helper.getNextLabel()
		#Registers
		targetReg = helper.getNextReg()
		
		c.checkType(argValues[0], "bool", endlabel, errorLabel)
		

		
		helper.addLLVMLabel(errorLabel)
		c.signalError(10)
		
		helper.addLLVMLabel(endlabel)
		helper.addLLVMInst(llvm_xor(targetReg, argValues[0], "4"), "Xor 3rd bit")
		
		helper.setLabel(endlabel)
		helper.ascend(targetReg)
		
	def traverse(self, helper):
		self.val.traverse(helper)

class strlen(expression):
	def __init__(self,strg):
		self.strg = strg
	def evaluate(self, env):
		strg = self.strg.evaluate(env).getString() 
		if(type(strg) != type("")):
			print "Error: strlen requires <str> found " + type(strg) + "\n"
		return len(strg)
		
	def traverse(self, helper):
		self.strg.traverse(helper)
		
	def toLLVM(self, helper):
		helper.descend("strlen")
		self.strg.toLLVM(helper)
		c = commonRoutines(helper)

		argValues = helper.getReturns()
		unMaskedIntReg = helper.getNextReg()
		targetReg = helper.getNextReg()

		#helper.addLLVMInst(llvm_and(unMaskedIntReg, helper.getReturns()[0], int('0xFFFFFFFC',16), "i32"), "Un-masking pointer to string")
		helper.addLLVMInst(llvm_call("stringLength", "i32", targetReg, helper.getReturns()[0], "i32"))
		helper.setLabel(helper.getLastLabel())
		helper.ascend(targetReg)
		
		#something with a c function
		

class substr(expression):
	def __init__(self,strg,s,e):
		self.strg = strg
		self.s = s
		self.e = e
	def evaluate(self, env):
		strg = self.strg.evaluate(env).getString() 
		s = self.s.evaluate(env)
		e = self.e.evaluate(env)
		if(type(strg) != type("")):
			print "Error: substr requires <str> found " + type(strg) + "\n"
		if(not((type(s) == type(0)) and (type(e) == type(0) ))):
			print "Error: start and end requires <int> found " + type(s) + " " + type(e) + "\n"
		return stringval(strg[s:e])
		
	def traverse(self, helper):
		self.strg.traverse(helper)
		self.s.traverse(helper)
		self.e.traverse(helper)

	def toLLVM(self, helper):
		helper.descend("substr")
		self.strg.toLLVM(helper)
		self.s.toLLVM(helper)
		self.e.toLLVM(helper)
		c = commonRoutines(helper)
		#sys.stderr.write("Arg values: " + str(helper.getReturns()))

		argValues = helper.getReturns()
		unMaskedIntReg = helper.getNextReg()
		targetReg = helper.getNextReg()
		

		helper.addLLVMInst(llvm_call("subString", "i32", targetReg, helper.getReturns()[0],"i32", helper.getReturns()[1], "i32", helper.getReturns()[2],"i32"))
		Reg1 = helper.getNextReg()
		Reg2 = helper.getNextReg()
		Reg3 = helper.getNextReg()
		Reg4 = helper.getNextReg()
		Reg5 = helper.getNextReg()
		Reg6 = helper.getNextReg()	
		Reg7 = helper.getNextReg()	
		stringReg = helper.getNextReg()
		ptrReg = helper.getNextReg()
	
		helper.addLLVMInst(llvm_malloc(Reg1, "%strobj"), "Malloc a string")
		helper.addLLVMInst(llvm_gep(Reg2,Reg1,"%strobj*",  0 , "i32" , 0 , "i32"), "Get the pointer to the first spot")   
		helper.addLLVMInst(llvm_store("2", Reg2))
		helper.addLLVMInst(llvm_gep(Reg3,Reg1,"%strobj*",  0 , "i32" , 1 , "i32"), "Get the pointer to slots") 
		helper.addLLVMInst(llvm_store("@empty_slots", Reg3, "%slots*","%slots*"), "Storing empty slots into the slots slot")
		
		helper.addLLVMInst(llvm_inttoptr(ptrReg, targetReg,"i32", "i32*"), "Turn the number into a pointer")
		helper.addLLVMInst(llvm_bitcast(stringReg, ptrReg, "i32*" , "i8*"), "Bitcast the read string to i8*")

		helper.addLLVMInst(llvm_gep(Reg5,Reg1,"%strobj*",  0 , "i32" , 2 , "i32"), "Get the pointer to string") 

		helper.addLLVMInst(llvm_store(stringReg, Reg5, "i8*", "i8*"), "Storing the pointer to the string val")
		helper.addLLVMInst(llvm_ptrtoint(Reg6, Reg1, "%strobj*", "i32"), "Making the string pointer into an int")
		helper.addLLVMInst(llvm_add(Reg7, Reg6, 1, "i32"), "Storing the pointer tag bit by adding one")

		helper.setLabel(helper.getLastLabel())
		helper.ascend(Reg7)


		#something with a c function

class strEq(expression):
	def __init__(self,strg1,strg2):
		self.strg1 = strg1
		self.strg2 = strg2
	def evaluate(self, env):
		strg1 = self.strg1.evaluate(env).getString() 
		strg2 = self.strg2.evaluate(env).getString() 
		if((type(strg1) != type("")) or (type(strg2) != type(""))):
			print "Error: strEq requires <str> and <str> found " + type(strg1) + " " + type(strg2) + "\n"
		return strg1 == strg2
		
	def traverse(self, helper):
		self.strg1.traverse(helper)
		self.strg2.traverse(helper)
		
	def toLLVM(self, helper):
		helper.descend("strEq")
		self.strg1.toLLVM(helper)
		self.strg2.toLLVM(helper)
		c = commonRoutines(helper)
		#sys.stderr.write("Arg values: " + str(helper.getReturns()))

		argValues = helper.getReturns()
		unMaskedIntReg = helper.getNextReg()
		targetReg = helper.getNextReg()
		
		helper.addLLVMInst(llvm_call("stringEq", "i32", targetReg, helper.getReturns()[0],"i32", helper.getReturns()[1], "i32"), "EQUALS STRINGS HUH?")
		helper.setLabel(helper.getLastLabel())
		helper.ascend(targetReg)

		
		#something with a c function

class strLess(expression):
	def __init__(self,strg1,strg2):
		self.strg1 = strg1
		self.strg2 = strg2
	def evaluate(self, env):
		strg1 = self.strg1.evaluate(env).getString()  
		strg2 = self.strg2.evaluate(env).getString()  
		if((type(strg1) != type("")) or (type(strg2) != type(""))):
			print "Error: strLess requires <str> and <str> found " + type(strg1) + " " + type(strg2) + "\n"
		return strg1 < strg2

	def traverse(self, helper):
		self.strg1.traverse(helper)
		self.strg2.traverse(helper)
		
	def toLLVM(self, helper):
		helper.descend("strless")
		self.strg1.toLLVM(helper)
		self.strg2.toLLVM(helper)
		#something with a c function
		c = commonRoutines(helper)

		argValues = helper.getReturns()
		unMaskedIntReg = helper.getNextReg()
		targetReg = helper.getNextReg()
		
		helper.addLLVMInst(llvm_call("stringLessThan", "i32", targetReg, helper.getReturns()[0],"i32", helper.getReturns()[1], "i32"))
		helper.setLabel(helper.getLastLabel())
		helper.ascend(targetReg)

class equals(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval
		rval = self.rval
		#print "Equals: lval:", lval, " rval:", rval, "\n"
		if(not isinstance(self.lval,jsobject)):			
			lval = self.lval.evaluate(env) 
			#print "lval evaluated: ", lval, "\n"
		if(not isinstance(self.rval,jsobject)):
			rval = self.rval.evaluate(env)
			#print "rval evaluated: ", rval, "\n"
		if(isinstance(lval,jsobject) == isinstance(rval,jsobject)):
			#print "lval and rval are objects, id's are: ", id(lval), ", ",id(rval), "\n"
			return id(lval) == id(rval)
		
		if((lval == rval)):
			return True
		return False
		
	def traverse(self, helper):
		self.lval.traverse(helper)
		self.rval.traverse(helper)
		
	def toLLVM(self, helper): 
		helper.descend("equals")
		self.lval.toLLVM(helper)
		self.rval.toLLVM(helper)
		
		argValues = helper.getReturns()
		#Labels
		#Registers
		nonExtendedResult = helper.getNextReg()
		preShiftReg = helper.getNextReg()
		postShiftReg =helper.getNextReg() 
		targetReg = helper.getNextReg()
		
		
#		helper.addLLVMLabel(endlabel) 
		helper.addLLVMInst(llvm_icmp_eq(nonExtendedResult, argValues[0], argValues[1]), "compare values")
		helper.addLLVMInst(llvm_zext(preShiftReg, nonExtendedResult, "i1", "i32"))
		helper.addLLVMInst(llvm_shl(postShiftReg, preShiftReg, "2"), "Shift result")
		helper.addLLVMInst(llvm_add(targetReg, postShiftReg, "3"), "add tag value")
		
		helper.setLabel(helper.getLastLabel())
		helper.ascend(targetReg)

class intQ(expression):
	def __init__(self,val):
		self.val = val
	def evaluate(self, env):
		val = self.val.evaluate(env)
		return (type(val) == type(0))
	
	def traverse(self, helper):
		self.val.traverse(helper)
		
	def toLLVM(self, helper):
		helper.descend("int?")
		self.val.toLLVM(helper)
		
		c = commonRoutines(helper)
		
		argValues = helper.getReturns()
		#Labels
		falseLabel = helper.getNextLabel()
		trueLabel = helper.getNextLabel()
		endLabel = helper.getNextLabel()
		#Registers
		targetReg = helper.getNextReg()
		
		c.checkType(argValues[0], "int", trueLabel, falseLabel)
		
		
		helper.addLLVMLabel(falseLabel, "not an int")
		helper.addLLVMInst(llvm_br(endLabel))
		
		helper.addLLVMLabel(trueLabel, "totally an int")
		helper.addLLVMInst(llvm_br(endLabel))
		
		helper.addLLVMLabel(endLabel, "phi that shit!")
		helper.addLLVMInst(llvm_phi(targetReg, "i32", "7", trueLabel, "3", falseLabel))
		
		helper.setLabel(endLabel)
		helper.ascend(targetReg)
		

class boolQ(expression):
	def __init__(self,val):
		self.val = val
	def evaluate(self, env):
		val = self.val.evaluate(env)
		return (type(val) == type(1==1))
	
	def traverse(self, helper):
		self.val.traverse(helper)
		
	def toLLVM(self, helper):
		helper.descend("bool?")
		self.val.toLLVM(helper)
		
		c = commonRoutines(helper)
		
		argValues = helper.getReturns()
		#Labels
		falseLabel = helper.getNextLabel()
		trueLabel = helper.getNextLabel()
		endLabel = helper.getNextLabel()
		#Registers
		targetReg = helper.getNextReg()
		
		c.checkType(argValues[0], "bool", trueLabel, falseLabel)
		
		
		helper.addLLVMLabel(falseLabel, "not a bool")
		helper.addLLVMInst(llvm_br(endLabel))
		
		helper.addLLVMLabel(trueLabel, "totally a bool")
		helper.addLLVMInst(llvm_br(endLabel))
		
		helper.addLLVMLabel(endLabel, "phi that shit!")
		helper.addLLVMInst(llvm_phi(targetReg, "i32", "7", trueLabel, "3", falseLabel))
		
		helper.setLabel(endLabel)
		helper.ascend(targetReg)

class floatQ(expression):
	def __init__(self,val):
		self.val = val
	def evaluate(self, env):
		val = self.val.evaluate(env)
		return (type(val) == type(0.0))
	
	def traverse(self, helper):
		self.val.traverse(helper)
		
	def toLLVM(self, helper):
		helper.descend("float?")
		self.val.toLLVM(helper)
		
		c = commonRoutines(helper)
		
		argValues = helper.getReturns()
		#Labels
		pointerLabel = helper.getNextLabel()
		falseLabel = helper.getNextLabel()
		trueLabel = helper.getNextLabel()
		endLabel = helper.getNextLabel()
		#Registers
		targetReg = helper.getNextReg()
		
		c.checkType(argValues[0], "pointer", pointerLabel, falseLabel)
		
		helper.addLLVMLabel(pointerLabel, "If the argument passed in is a pointer")
		objType =  c.loadObjType(argValues[0])
		c.checkType(objType, "float", trueLabel, falseLabel)
		
		helper.addLLVMLabel(falseLabel, "not an int")
		helper.addLLVMInst(llvm_br(endLabel))
		
		helper.addLLVMLabel(trueLabel, "totally an int")
		helper.addLLVMInst(llvm_br(endLabel))
		
		helper.addLLVMLabel(endLabel, "phi that shit!")
		helper.addLLVMInst(llvm_phi(targetReg, "i32", "7", trueLabel, "3", falseLabel))
		
		helper.setLabel(endLabel)
		helper.ascend(targetReg)

class voidQ(expression):
	def __init__(self,val):
		self.val = val
	def evaluate(self, env):
		val = self.val.evaluate(env)
		return (type(val) == type(void()))
	
	def traverse(self, helper):
		self.val.traverse(helper)
	
	def toLLVM(self, helper):	
		helper.descend("bool?")
		self.val.toLLVM(helper)
		
		c = commonRoutines(helper)
		
		argValues = helper.getReturns()
		#Labels
		falseLabel = helper.getNextLabel()
		trueLabel = helper.getNextLabel()
		endLabel = helper.getNextLabel()
		#Registers
		targetReg = helper.getNextReg()
		
		c.checkType(argValues[0], "bool", trueLabel, falseLabel)
		
		
		helper.addLLVMLabel(falseLabel, "not a bool")
		helper.addLLVMInst(llvm_br(endLabel))
		
		helper.addLLVMLabel(trueLabel, "totally a bool")
		helper.addLLVMInst(llvm_br(endLabel))
		
		helper.addLLVMLabel(endLabel, "phi that shit!")
		helper.addLLVMInst(llvm_phi(targetReg, "i32", "7", trueLabel, "3", falseLabel))
		
		helper.setLabel(endLabel)
		helper.ascend(targetReg)

class stringQ(expression):
	def __init__(self,val):
		self.val = val
	def evaluate(self, env):
		val = self.val.evaluate(env)
		return (isinstance(val,stringval))
	
	def traverse(self, helper):
		self.val.traverse(helper)
	
	def toLLVM(self, helper):
		helper.descend("string?")
		self.val.toLLVM(helper)
		
		c = commonRoutines(helper)
		
		argValues = helper.getReturns()
		#Labels
		pointerLabel = helper.getNextLabel()
		falseLabel = helper.getNextLabel()
		trueLabel = helper.getNextLabel()
		endLabel = helper.getNextLabel()
		#Registers
		targetReg = helper.getNextReg()
		
		c.checkType(argValues[0], "pointer", pointerLabel, falseLabel)
		
		helper.addLLVMLabel(pointerLabel, "If the argument passed in is a pointer")
		objType =  c.loadObjType(argValues[0])
		c.checkType(objType, "string", trueLabel, falseLabel)
		
		helper.addLLVMLabel(falseLabel, "not an int")
		helper.addLLVMInst(llvm_br(endLabel))
		
		helper.addLLVMLabel(trueLabel, "totally an int")
		helper.addLLVMInst(llvm_br(endLabel))
		
		helper.addLLVMLabel(endLabel, "phi that shit!")
		helper.addLLVMInst(llvm_phi(targetReg, "i32", "7", trueLabel, "3", falseLabel))
		
		helper.setLabel(endLabel)
		helper.ascend(targetReg)

class instanceof(expression):
	def __init__(self,obj,val):
		self.val = val
		self.obj = obj
	def evaluate(self, env):
		obj = self.obj.evaluate(env)
		if(not isinstance(obj,jsobject)):
			return False
		else:
			try:
				newobj = obj.access('constructor')
				val = self.val.evaluate(env)
				return newobj == val
			except VarNotFoundExcpt:
				return False
	
	def traverse(self, helper):
		self.val.traverse(helper)
		self.obj.traverse(helper)

	def toLLVM(self, helper):
		#fix me
		helper.descend("instanceof")

		self.val.toLLVM(helper)
		self.obj.toLLVM(helper)

		c = commonRoutines(helper)
		
		argValues = helper.getReturns()
		#sys.stderr.write("What this RETURN: " + str(argValues)+ "\n")
		checkInstance = helper.getNextLabel()
		getOut = helper.getNextLabel()
		getOutAgain = helper.getNextLabel()
		exit = helper.getNextLabel()
		
		valType = c.loadObjType(argValues[0])
		objType = c.loadObjType(argValues[1])

		#sys.stderr.write("HERE: " + str(valType) + " : " + str(objType)+ "\n")
		compReg = helper.getNextReg()
		isequal = helper.getNextReg()
		check = helper.getNextReg()
		slotsReg = helper.getNextReg()
		intSlots = helper.getNextReg()
		intSlots2 = helper.getNextReg()
		unMaskedIntReg = helper.getNextReg()


		c.checkType(objType,0, checkInstance,getOut)

		helper.addLLVMLabel(getOut)
		#helper.addLLVMInst(llvm_store(3,compReg, "i32"), "Store the false answer here") 
		helper.addLLVMInst(llvm_br(exit), "Gogogo")

		helper.addLLVMLabel(checkInstance)
		
		ptr = c.testAndUnmaskPointer(argValues[1],"%jsobject*")
		helper.addLLVMInst(llvm_gep(slotsReg, ptr, "%jsobject*", 0 , "i32", 1, "i32"), "Get the slots out of the object") 
		helper.addLLVMInst(llvm_load(intSlots,slotsReg, "%slots*"), "Get the slots object out")
		helper.addLLVMInst(llvm_ptrtoint(intSlots2, intSlots, "%slots*"), "make the slots object pointer an int")
		con = c.fetchSlotsVar(intSlots2, 0)
		helper.addLLVMInst(llvm_icmp_eq(check, con, argValues[0]), "See if the constructor is equal to the value referenced")
		helper.addLLVMInst(llvm_brc(check, exit, getOut), "Branch!")
		#helper.addLLVMLine("call void @printmarker(i32 "+ str(3) +")")
		#helper.addLLVMInst(llvm_br(exit), "Branch to exit ") 
		
		targetReg = helper.getNextReg()
		helper.addLLVMLabel(exit)
		helper.addLLVMInst(llvm_phi(targetReg, "i32", "3", getOut,"7",checkInstance), "Get out!")  
		#helper.debugPrint(targetReg,"a")
		helper.setLabel(helper.getLastLabel())
		helper.ascend(targetReg)

class closureQ(expression):
	def __init__(self,val):
		self.val = val
	def evaluate(self, env):
		return isinstance(self.val,closure)
		
	def traverse(self, helper):
		self.val.traverse(helper)
		
	def toLLVM(self, helper):
		helper.descend("closure?")
		self.val.toLLVM(helper)
		
		c = commonRoutines(helper)
		
		argValues = helper.getReturns()
		#Labels
		pointerLabel = helper.getNextLabel()
		falseLabel = helper.getNextLabel()
		trueLabel = helper.getNextLabel()
		endLabel = helper.getNextLabel()
		#Registers
		targetReg = helper.getNextReg()
		
		c.checkType(argValues[0], "pointer", pointerLabel, falseLabel)
		
		helper.addLLVMLabel(pointerLabel, "If the argument passed in is a pointer")
		objType =  c.loadObjType(argValues[0])
		c.checkType(objType, "closure", trueLabel, falseLabel)
		
		helper.addLLVMLabel(falseLabel, "not an int")
		helper.addLLVMInst(llvm_br(endLabel))
		
		helper.addLLVMLabel(trueLabel, "totally an int")
		helper.addLLVMInst(llvm_br(endLabel))
		
		helper.addLLVMLabel(endLabel, "phi that shit!")
		helper.addLLVMInst(llvm_phi(targetReg, "i32", "7", trueLabel, "3", falseLabel))
		
		helper.setLabel(endLabel)
		helper.ascend(targetReg)

class plainQ(expression):
	def __init__(self,val):
		self.val = val
	def evaluate(self, env):
		val = self.val.evaluate(env)
		return isinstance(val,jsobject) and not isinstance(val,closure) and not isinstance(val,stringval)
		
	def traverse(self, helper):
		self.val.traverse(helper)
	
	def toLLVM(self, helper):
		helper.descend("object?")
		self.val.toLLVM(helper)
		
		c = commonRoutines(helper)
		
		argValues = helper.getReturns()
		#Labels
		pointerLabel = helper.getNextLabel()
		falseLabel = helper.getNextLabel()
		trueLabel = helper.getNextLabel()
		endLabel = helper.getNextLabel()
		#Registers
		targetReg = helper.getNextReg()
		
		c.checkType(argValues[0], "pointer", pointerLabel, falseLabel)
		
		helper.addLLVMLabel(pointerLabel, "If the argument passed in is a pointer")
		objType =  c.loadObjType(argValues[0])
		c.checkType(objType, "plain object", trueLabel, falseLabel)
		
		helper.addLLVMLabel(falseLabel, "not an int")
		helper.addLLVMInst(llvm_br(endLabel))
		
		helper.addLLVMLabel(trueLabel, "totally an int")
		helper.addLLVMInst(llvm_br(endLabel))
		
		helper.addLLVMLabel(endLabel, "phi that stuff!")
		helper.addLLVMInst(llvm_phi(targetReg, "i32", "7", trueLabel, "3", falseLabel))
		
		helper.setLabel(endLabel)
		helper.ascend(targetReg)

class printOut(expression):
	def __init__(self,strg):
		self.strg = strg
	def evaluate(self, env):
		s =  self.strg.evaluate(env)
		print str(s)
		#sys.stdout.flush()
	
	def traverse(self, helper):
		self.strg.traverse(helper)
		
	def toLLVM(self, helper):
		helper.descend("printOut")
		self.strg.toLLVM(helper)
		helper.addLLVMInst(llvm_call("printvalue", "void", None, helper.getReturns()[0], "i32"))
#		self.addLLVMLine("call void @printvalue(i32 "+ helper.getReturns()[0]+ ")")
		helper.setLabel(helper.getLastLabel())
		helper.ascend(helper.getReturns()[0])
		

class readLine(expression):
	def evaluate(self, env):
		strg = raw_input()
		return stringval(str(strg) + "\n")
	
	def traverse(self, helper):
		pass
	
	def toLLVM(self, helper):
		helper.descend("readLine")

		targetReg = helper.getNextReg()
		helper.addLLVMInst(llvm_call("read_line", "i32", targetReg), "Just read it already!")
		

		Reg1 = helper.getNextReg()
		Reg2 = helper.getNextReg()
		Reg3 = helper.getNextReg()
		Reg4 = helper.getNextReg()
		Reg5 = helper.getNextReg()
		Reg6 = helper.getNextReg()	
		Reg7 = helper.getNextReg()	
		stringReg = helper.getNextReg()
		ptrReg = helper.getNextReg()
	
		helper.addLLVMInst(llvm_malloc(Reg1, "%strobj"), "Malloc a string")
		helper.debugPrint(targetReg, "a")
		helper.addLLVMInst(llvm_gep(Reg2,Reg1,"%strobj*",  0 , "i32" , 0 , "i32"), "Get the pointer to the first spot")   
		helper.addLLVMInst(llvm_store("2", Reg2))
		helper.addLLVMInst(llvm_gep(Reg3,Reg1,"%strobj*",  0 , "i32" , 1 , "i32"), "Get the pointer to slots") 
		helper.addLLVMInst(llvm_store("@empty_slots", Reg3, "%slots*","%slots*"), "Storing empty slots into the slots slot")
		
		helper.addLLVMInst(llvm_inttoptr(ptrReg, targetReg,"i32", "i32*"), "Turn the number into a pointer")
		helper.addLLVMInst(llvm_bitcast(stringReg, ptrReg, "i32*" , "i8*"), "Bitcast the read string to i8*")

		helper.addLLVMInst(llvm_gep(Reg5,Reg1,"%strobj*",  0 , "i32" , 2 , "i32"), "Get the pointer to string") 

		helper.addLLVMInst(llvm_store(stringReg, Reg5, "i8*", "i8*"), "Storing the pointer to the string val")
		helper.addLLVMInst(llvm_ptrtoint(Reg6, Reg1, "%strobj*", "i32"), "Making the string pointer into an int")
		helper.addLLVMInst(llvm_add(Reg7, Reg6, 1, "i32"), "Storing the pointer tag bit by adding one")

		helper.setLabel(helper.getLastLabel())
		helper.ascend(Reg7)





